
package ProOF.apl.methods.GA.population;

import ProOF.com.LinkerParameters;
import ProOF.com.LinkerResults;
import ProOF.com.runner.ExceptionForceFinish;
import ProOF.opt.abst.problem.meta.Solution;
import ProOF.opt.abst.problem.meta.codification.Codification;
import ProOF.opt.abst.problem.meta.objective.SingleObjective;
import java.util.Collections;

/**
 *
 * @author Hossomi
 */
public class PopulationRoulette extends aPopulation {
    private double w[];

    @Override
    public void start() throws Exception {
        super.start();
        w = new double[size];
    }
    
	@Override
	public void evolve() throws Exception {
        Solution child;
        Solution parents[];
        Codification codif;
        boolean add;
        
        System.out.println("Starting evolution...");
        
        // Start evolution
		while (!stop.end()) {
            
            // Select parents
            parents = select();
            add = false;
            
            // Try crossover
            if (problem.rmd.nextDouble() < crossRate) {
                child = opSet.crossover( parents[0], parents[1] );
                add = true;
            }
            else {
                codif = problem.NewCodification();
                codif.Copy(problem, parents[0].codif());
                child = problem.NewSolution(codif);
            }

            // Try mutation
            if (problem.rmd.nextDouble() < mutRate) {
                opSet.mutation(child);
                add = true;
            }

            // Only try to add transformed individuals
            // Population convergence is not interesting here
            if (add) {
                // Evaluate
                problem.evaluate(child);

                // Try to insert
                if (insert(child)) {
                    organize();
                }
            }
        }
	}

    @Override
    public Solution[] select() throws Exception {
        double x;
        int p1, p2;
        
        calculateWeight();
        
        // Select first
        
        x = problem.rmd.nextDouble();
        p1 = 0;
        while( p1 < size - 1 && x > w[p1] )
            p1++;
        
        //System.out.printf("Selected p1: %d\n", p1);
        
        // Select second
        
        int attempts = 10;
        do {
            if (attempts == 0) {
                System.out.println("Warning: roulette wheel failed...");
                reinitialize();
                calculateWeight();
                attempts = 10;
            }
            
            x = problem.rmd.nextDouble();
            p2 = 0;
            while( p2 < size - 1 && x > w[p2] )
                p2++;
            //System.out.printf("%d (x = %5.5f)\n", p2, x);
            attempts--;
            
        } while (p1 == p2);
        //System.out.printf("%d\n", p2);
        
        Solution parents[] = { individuals.get(p1), individuals.get(p2) };
        return parents;
    }
    
    public void organize() {
        Collections.sort(individuals);
    }
    
    public void calculateWeight() {
        double total = 0.0;
        double sum = 0.0;
        double worstFitness;
        
        organize();
        
        // Calculate weights
        
        worstFitness = ((SingleObjective) worst.obj()).abs_value();
        
        //System.out.print("\nPeso A: ");
        for (int i = 0; i < size; i++) {
            w[i] = worstFitness - ((SingleObjective) individuals.get(i).obj()).abs_value();
            total += w[i];
        }
        
        //System.out.printf("\nPeso B: ");
        for (int i = 0; i < size; i++) {
            w[i] = sum + w[i]/total;
            sum = w[i];
            //System.out.printf("%2.2f ", w[i]);
        }
        //System.out.println();
    }
    
	@Override
	public String name() {
		return "Pop. Roulette";
	}	

}
